<?php
/**
 * @package       system
 * @subpackage    filters
 */

/**
 * This filter catches a ServiceValidationException an transforms its message in a
 * {@link JsCall} to show it, when the call is a xmlHttpRequest.
 */
class ServiceExceptionFilter extends sfFilter
{
    
    public function execute($filterChain) {

        if (
            $this->getContext()->getRequest()->isXmlHttpRequest()
            || $this->getContext()->getRequest()->hasParameter('iframeAjaxUpload')
        ){
            try {
                $filterChain->execute();
            }
            catch(ServiceValidationException $e) {
                $request  = $this->getContext()->getRequest();
                $response = $this->getContext()->getResponse();
                $jsCall = $response->getJsCallReference();
                // errors to feedback...
                $errorToFeedbackFieldNames = $response->getTransferErrorToFeedbackFieldNames();
                $this->transferErrorsToFeedback($e, $jsCall, $errorToFeedbackFieldNames);
                // errors to fields...
                $fieldIdPrefix = $response->getFieldIdPrefix();
                $errorFieldNames = $response->getTransferErrorFieldNames();
                ##### Escolhe o objeto que vai receber o retorno
                $jsObjName = $request->getParameter('jsObjName','UtilC');
                $this->transferErrorsToCall($e, $jsCall, $errorFieldNames, $fieldIdPrefix, false, $jsObjName);
                if($e->hasError()) {
                    $msgs = 'SERVICE VALIDATION ERRORS (NOT TREATED):<BR/>'."\n";
                    foreach($e->getErrors() as $error) {
                        $msgs .= '['. $error['property'] . ']' . $error['message'].'<br/>';
                    }
                    $msg =
                        '<b>[ServiceValidationException caught by ServiceExceptionFilter] Error on Service Input Data!</b><br/><br/>'
                        .'<i>The following errors should be assigned to a form field or treated on the controller layer:</i>'
                        .'<pre>'
                        .$msgs
                        ."\n\n"
                        .$e->getTraceAsString()
                        .'</pre>';
                    $request = $this->getContext()->getRequest();
                    $content =
                       $jsCall
                       ->addCommand('UtilC','showBigFeedback')
                       ->addPHPParam('message',$msg)
                       ->toJson();
                }
            }
            catch(ServiceException $e) {
                $response = $this->getContext()->getResponse();
                $jsCall = $response->getJsCallReference();
                //$jsCall->showFeedback(GeneralMessages::SERVICE_EXCEPTION_PREFIX.'['.get_class($e).']'.$e->getMessage().print_r($e->getTrace(),1));
                $jsCall->showFeedback(GeneralMessages::SERVICE_EXCEPTION_PREFIX.'['.get_class($e).']'.$e->getMessage());
                //throw $e;
            }
        }
        else {
            $filterChain->execute();
        }
    }

    function transferErrorsToFeedback(
        ServiceValidationException $e,
        JsCall $jsCall,
        $fields
    ){
        $message = '';
        foreach($e->getErrors() as $k=>$error) {
            if(in_array($error['property'],$fields)) {
                $message .= 'Error on field '.$error['property'].' - "'.$error['message']."\".<br/>\n";
                $jsCall->addFeedback($message);
                $e->removeError($k);
            }
        }
    }

    function transferErrorsToCall(
        ServiceValidationException $e,
        JsCall $jsCall,
        $fields,
        $fieldIdPrefix,
        $rethrow = true,
        $jsController // o objeto js responsável por mostrar o erro no formulário
    ) {
        if($jsController == 'UtilC') {
            #### se for o UtilC, usa o método antigo, com o fieldIdPrefix
            foreach($e->getErrors() as $k=>$error) {
                if(in_array($error['property'],$fields)) {
                    $jsCall
                        ->addCommand($jsController,'showFormError')
                        ->addPHPParam('fieldName',$fieldIdPrefix.'-'.$error['property'])
                        ->addPHPParam('message',$error['message']);
                    $e->removeError($k);
                }
            }
        }
        else {
            ### se já for outro objeto, usa o padrão novo, com o nome do objeto e o nome do campo:
            foreach($e->getErrors() as $k=>$error) {
                if(in_array($error['property'],$fields)) {
                    $jsCall
                        ->addCommand($jsController,'showFormError')
                        ->addPHPParam('fieldName',$error['property']) #### unica diferença!
                        ->addPHPParam('message',$error['message']);
                    $e->removeError($k);
                }
            }
        }
        

        if($rethrow && $e->hasError()) {
            throw $e;
        }
    }

}
?>